package node_login

import (
	"fmt"
	"sanguo/cluster"
	"time"
	//"math/rand"
	ss_msg "sanguo/protocol/ss/message"
	ss_rpc "sanguo/protocol/ss/rpc"
	"sanguo/rpc/synctoken"

	"github.com/golang/protobuf/proto"
	"github.com/sniperHW/kendynet"
	//"strings"
	//"strconv"
)

var gameMap map[string]*Game
var gameList []*Game //当前可用的网关列表

type Game struct {
	service   cluster.Service //集群内地址
	addr      string          //对外服务地址
	playerNum int32
	deadline  time.Time
}

//产生令牌
func genToken(user string) string {
	//todo:使用更合理的算法
	return "token" + user
}

func hash(user string) int {
	return 0
}

func GetGame(user string, callback func(error, string, string)) {
	hashCode := hash(user)
	size := len(gameList)
	if size > 0 {
		i := hashCode % size
		game := gameList[i]
		arg := &ss_rpc.SynctokenReq{
			Userid: proto.String(user),
			Token:  proto.String(genToken(user)),
		}
		//将令牌同步给选中的game
		synctoken.AsynCall(game.service.ToPeerID(), arg, 1000*10, func(result *ss_rpc.SynctokenResp, err error) {
			if nil != err {
				callback(err, "", "")
			} else {
				callback(nil, game.addr, result.GetToken())
			}
		})
	} else {
		//没用可供使用的gate
		callback(fmt.Errorf("no avalilable game"), "", "")
	}
}

func onReportGame(_ kendynet.StreamSession, msg proto.Message) {
	report := msg.(*ss_msg.ReportGame)

	//Infoln("onReportGame:", report.GetPeerID(), report.GetExternalAddr())

	g, ok := gameMap[report.GetPeerID()]

	//Infoln(g, ok, gameMap)

	if ok {
		g.playerNum = report.GetPlayerNum()
		g.deadline = time.Now().Add(time.Second * 20)
		//Infoln("old game")
	} else {
		g = &Game{}
		g.service, _ = cluster.PeerID2Service(cluster.PeerID(report.GetPeerID()))
		g.addr = report.GetExternalAddr()
		g.playerNum = report.GetPlayerNum()
		g.deadline = time.Now().Add(time.Second * 20)
		gameMap[report.GetPeerID()] = g
		gameList = append(gameList, g)
	}
}

func init() {

	gameMap = map[string]*Game{}
	gameList = []*Game{}

	cluster.Register(&ss_msg.ReportGame{}, onReportGame)
	go func() {
		for {
			//交给cluster的任务队列单线程执行
			cluster.PostTask(func() {
				gameList = gameList[0:0]
				now := time.Now()
				for k, v := range gameMap {
					if v.deadline.After(now) {
						gameList = append(gameList, v)
					} else {
						delete(gameMap, k)
					}
				}
			})
			time.Sleep(time.Second * 5)
		}
	}()
}
